Cargar Archivos en Node
DigitalOcean, utilizando la infraestructura de S3 de Amazon, permite la manipulación de archivos (cargar, ver y eliminar) de manera eficiente. Con Node.js, esta manipulación puede ser optimizada y resulta fácil de configurar y utilizar.
Paquetes a utilizar:
npm install @aws-sdk/client-s3
npm install express-fileupload
Variables de entorno:
S3_ENDPOINT
BUCKET_NAME
BUCKED_ENDPOINT
AWS_ACCESS_KEY
AWS_SECRET_ACCESS_KEY
AWS_REGION
-
S3_ENDPOINT
- Descripción: URL del servidor para acceder a los servicios de almacenamiento en la nube (como Amazon S3 o DigitalOcean Spaces).
- Ejemplo:
https://nyc3.digitaloceanspaces.com
-
BUCKET_NAME
- Descripción: Nombre del contenedor donde se almacenan los archivos.
- Ejemplo:
my-app-bucket
-
BUCKED_ENDPOINT
- Descripción: URL base para acceder a los archivos en el bucket.
- Ejemplo:
https://my-app-bucket.nyc3.digitaloceanspaces.com
-
AWS_ACCESS_KEY
- Descripción: Clave pública para autenticar solicitudes a AWS.
- Ejemplo:
AKIAIOSFODNN7EXAMPLE
-
AWS_SECRET_ACCESS_KEY
- Descripción: Clave secreta para firmar solicitudes a AWS.
- Ejemplo:
wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
-
AWS_REGION
- Descripción: Región geográfica de AWS donde está el bucket.
- Ejemplo:
us-east-1
Con estos paquetes y variables, crearemos un controlador para la carga de archivos, un servicio para conectar con DigitalOcean y manipular dichos archivos, así como las rutas necesarias.
No olvides agregar tu configuración de express-fileupload
La carga de archivos se encuentra disponible en el esqueleto de node-mongo.
Cómo Empezar
El proyecto se divide en tres componentes:
router
service
controller
Upload.route.js
Este archivo define las rutas y validaciones para las operaciones de carga, eliminación y obtención de archivos.
// upload.validations.js
const { query, body } = require("express-validator");
const validationFolderQuery = [
query("folder").notEmpty().isString().withMessage("It is required")
]
const validationDeleteQuery = [
query("file").notEmpty().isString().withMessage("It is required")
]
const validationDeleteMultiple = [
query("folder").notEmpty().isString().withMessage("It is required"),
body("files").notEmpty().isArray().withMessage("It is required")
]
module.exports = {
validationFolderQuery,
validationDeleteQuery,
validationDeleteMultiple
};
// upload.route.js
const { Router } = require("express");
const { uploadFile, deleteArrayFile, deleteFile, getTodoFiles } = require("./upload.controller");
const { validationFolderQuery, validationDeleteQuery, validationDeleteMultiple } = require("./upload.validations");
const { validateMiddlewareChecks } = require("../../../middleware/validation.middleware");
const routes = Router();
routes.post(
"/uploadFile",
[
...validationFolderQuery,
validateMiddlewareChecks
],
uploadFile
)
routes.delete(
"/deleteFile",
[
...validationFolderQuery,
...validationDeleteQuery,
validateMiddlewareChecks
],
deleteFile
)
routes.get(
"/getFiles",
[
...validationFolderQuery,
validateMiddlewareChecks
],
getTodoFiles
)
routes.post(
"/deleteArrayFiles",
[
...validationDeleteMultiple,
validateMiddlewareChecks
],
deleteArrayFile
)
module.exports = routes;
Upload.controller.js
El controlador se encarga de procesar las solicitudes y devolver las respuestas necesarias para el frontend.
// upload.controller.js
const { response } = require("express");
const { getSuccessfulResponse, errorHandler } = require("../../../helpers/responses");
const { fileUpload, fileDeleted, arrayFilesDeleted, getAllFiles } = require("./upload.service")
const pathFolder = 'projectName/folder'
const uploadFile = async (req, res = response) => {
if (!req.files || !req.files.file) return res.json({ msg: "No files uploaded" });
const { folder } = req.query;
const { file } = req.files;
try {
const url = await fileUpload(file, folder);
return getSuccessfulResponse(res, { status: 0, msg: "File was uploaded successfully", payload: url });
} catch (error) {
return errorHandler({ res, message: error.message, path: req.originalUrl })
}
}
const deleteFile = async (req, res = response) => {
const { file, folder } = req.query;
try {
const url = await fileDeleted(file, folder);
return getSuccessfulResponse(res, { status: 0, msg: "File was delete successfully", payload: url });
} catch (error) {
return errorHandler({ res, message: error.message, path: req.originalUrl })
}
}
const deleteArrayFile = async (req, res = response) => {
const { folder } = req.query;
const { files } = req.body;
try {
const objects = files.map(key => ({ Key: `${folder}/${key}` }));
const arrayFile = await arrayFilesDeleted(objects);
return getSuccessfulResponse(res, { status: 0, msg: "File was delete successfully", payload: arrayFile });
} catch (error) {
return errorHandler({ res, message: error.message, path: req.originalUrl })
}
}
const getTodoFiles = async (req, res = response) => {
const { folder } = req.query;
const data = await getAllFiles(folder)
const filesByFolder = data.map(({ Key, LastModified, Size }) => ({
Key,
LastModified,
Size
}));
return getSuccessfulResponse(res, { status: 0, msg: "Gets Files", payload: filesByFolder });
}
module.exports = {
uploadFile,
deleteFile,
getTodoFiles,
deleteArrayFile
}
Upload.service.js
El servicio se encarga de interactuar con AWS S3 o DigitalOcean Spaces para realizar las operaciones de carga, eliminación y obtención de archivos.
//upload.service.js
const { S3Client, PutObjectCommand, DeleteObjectCommand, DeleteObjectsCommand, ListObjectsV2Command } = require("@aws-sdk/client-s3");
const s3 = new S3Client({
endpoint: process.env.S3_ENDPOINT, // Configura el endpoint (puede ser AWS o DigitalOcean Spaces)
region: process.env.AWS_REGION, // Especifica la región si es necesario
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY
}
});
const fileUpload = async (file, path) => {
const keyName = `${path}/${Date.now().toString()}-${file.name}`;
const uploadCommand = new PutObjectCommand({
ACL: "public-read",
Bucket: process.env.BUCKET_NAME,
Key: keyName,
Body: file.data
});
await s3.send(uploadCommand);
const urlFile = `${process.env.BUCKED_ENDPOINT}/${keyName}`;
return urlFile;
};
const fileDeleted = async (file, path) => {
const keyName = `${path}/${file}`;
const deleteCommand = new DeleteObjectCommand({
Bucket: process.env.BUCKET_NAME,
Key: keyName
});
await s3.send(deleteCommand);
const urlFile = `${process.env.BUCKED_ENDPOINT}/${keyName}`;
return urlFile;
};
const arrayFilesDeleted = async (objects = []) => {
const deleteCommand = new DeleteObjectsCommand({
Bucket: process.env.BUCKET_NAME,
Delete: { Objects: objects }
});
const { Deleted } = await s3.send(deleteCommand);
return Deleted;
};
const getAllFiles = async (folder) => {
const listCommand = new ListObjectsV2Command({
Bucket: process.env.BUCKET_NAME,
Prefix: folder
});
const { Contents } = await s3.send(listCommand);
return Contents;
};
module.exports = {
fileUpload,
fileDeleted,
arrayFilesDeleted,
getAllFiles,
}